home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Producer's Bible / Multimedia Producer's Bible.iso / mac / mTropolis / mTropolis Sampler Files / mFactory Object Model Examples / Source / Gravity / Gravity.c next >
Encoding:
C/C++ Source or Header  |  1996-01-04  |  9.7 KB  |  361 lines  |  [TEXT/MMCC]

  1. /*    Gravity.c
  2. **
  3. **    Copyright 1995, mFactory, Inc.
  4. **    All rights reserved.
  5. */
  6.  
  7. #include "Gravity.h"
  8. #include <math.h>
  9.     
  10. #define kActivatePopup         6                                                // DITL indices
  11. #define kTerminatePopup        8
  12. #define kGravConstField        11
  13.  
  14. #define kMassAttrib            ((CompID *) "mass\0\0\0\0\0\0\0\0\0\0\0\0")        // attributes
  15. #define kResVectorAttrib    ((CompID *) "resultantvector\0")
  16.  
  17. #define kTimePeriod            10                                                // milliseconds
  18.  
  19.  
  20. /*    Initial entry point
  21. */
  22.  
  23. MCompMainFuncDcl MCompMainName(MInitInfo *initInfo)
  24. {
  25.     MDefineComponent(GravitySrvComp, kMCanDragOff);
  26.     MInheritClass(MComponent, kMCompNumProcs, kMBaseCompSlot);
  27.  
  28.     // MComponent methods we must override
  29.  
  30.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompConstructor, MCompConstructor);
  31.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompCopy, MCompCopy);
  32.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompCopyConstructor, MCompCopyConstructor);
  33.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompDestructor, MCompDestructor);
  34.  
  35.     // MComponent methods we choose to override
  36.  
  37.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompEditorOpen, MCompEditorOpen);
  38.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompEditorAccept, MCompEditorAccept);
  39.  
  40.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompGetSaveInfo, MCompGetSaveInfo);
  41.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompSaveComponent, MCompSaveComponent);
  42.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompRestoreComponent, MCompRestoreComponent);
  43.  
  44.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompProcessMessage, MCompProcessMessage);
  45.     
  46.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompGetAttribute, MCompGetAttribute);
  47.  
  48.     MDefineMethod(kGravitySrvSlot, kMBaseCompSlot, kMCompAdaptIDs, MCompAdaptIDs);
  49.  
  50.     // Introduce our own methods
  51.  
  52.     MDefineMethod(kGravitySrvSlot, kGravitySrvSlot, kGravitySrvTask, GravitySrvTask);
  53.  
  54.     MConnectCommonServices(initInfo);
  55.     
  56.     MEndComponentDef;
  57. }
  58.  
  59.  
  60. /*    Initialize component
  61. */
  62.  
  63. static MErr MCompConstructor(GravitySrvComp *self, MObjectRef *mRef)
  64. {
  65.     MInitEvent(self->f_enableEvent, kMParentEnabled, 0);
  66.     MInitEvent(self->f_disableEvent, kMNone, 0);
  67.     MInitDouble(self->f_constant, 1.0);
  68.     return kMNoCompErr;
  69. }
  70.  
  71.  
  72. /*    Copy component data
  73. */
  74.  
  75. static MErr MCompCopy(GravitySrvComp *self, GravitySrvComp *previousSelf)
  76. {
  77.     MCopyEvent(self->f_enableEvent, previousSelf->f_enableEvent);
  78.     MCopyEvent(self->f_disableEvent, previousSelf->f_disableEvent);
  79.     MCopyDouble(self->f_constant, previousSelf->f_constant);
  80.     return kMNoCompErr;
  81. }
  82.  
  83.  
  84. /*    Copy component
  85. */
  86.  
  87. static MErr MCompCopyConstructor(GravitySrvComp *self, GravitySrvComp *previousSelf, MObjectRef *mRef)
  88. {
  89.     MCompConstructor(self, mRef);
  90.     return MCompCopy(self, previousSelf);
  91. }
  92.  
  93.  
  94. /*    Dispose component
  95. */
  96.  
  97. static MErr MCompDestructor(GravitySrvComp *self)
  98. {
  99.     MDisposeEvent(self->f_enableEvent);
  100.     MDisposeEvent(self->f_disableEvent);
  101.     MDisposeDouble(self->f_constant);
  102.     return kMNoCompErr;
  103. }
  104.  
  105.  
  106. /*    Open component dialog
  107. */
  108.  
  109. static MErr MCompEditorOpen(GravitySrvComp *self, void *editor, short editorType)
  110. {
  111.     if ( editorType == kMDialogEditorType ) {
  112.         MSetEditorItem(editor, kActivatePopup, (MDataType *) &self->f_enableEvent);
  113.         MSetEditorItem(editor, kTerminatePopup, (MDataType *) &self->f_disableEvent);
  114.         MSetEditorItem(editor, kGravConstField, (MDataType *) &self->f_constant);
  115.         return kMNoCompErr;
  116.     } else
  117.         return kMUnableToComplyCompErr;
  118. }
  119.  
  120.  
  121. /*    Close component dialog
  122. */
  123.  
  124. static MErr MCompEditorAccept(GravitySrvComp *self, void *editor)
  125. {
  126.     MGetEditorItem(editor, kActivatePopup, (MDataType *) &self->f_enableEvent);
  127.     MGetEditorItem(editor, kTerminatePopup, (MDataType *) &self->f_disableEvent);
  128.     MGetEditorItem(editor, kGravConstField, (MDataType *) &self->f_constant);
  129.     return kMNoCompErr;
  130. }
  131.  
  132.  
  133. /*    Provide save information
  134. */
  135.  
  136. static MErr MCompGetSaveInfo(GravitySrvComp *self, MFileIOServ *file, long saveInfo, short *rev, long *len)
  137. {
  138.     long    valueSize;
  139.  
  140.     MSizeOfValue(file, &self->f_enableEvent, &valueSize);
  141.     *len = valueSize;
  142.     MSizeOfValue(file, &self->f_disableEvent, &valueSize);
  143.     *len += valueSize;
  144.     MSizeOfValue(file, &self->f_constant, &valueSize);
  145.     *len += valueSize;
  146.  
  147.     *rev = kGravitySrvRev;
  148.     return kMNoCompErr;
  149. }
  150.  
  151.  
  152. /*    Save component
  153. */
  154.  
  155. static MErr MCompSaveComponent(GravitySrvComp *self, MFileIOServ *file, long saveInfo)
  156. {
  157.     MWriteValue(file, &self->f_enableEvent);
  158.     MWriteValue(file, &self->f_disableEvent);
  159.     MWriteValue(file, &self->f_constant);
  160.  
  161.     return kMNoCompErr;
  162. }
  163.  
  164.  
  165. /*    Restore component
  166. */
  167.  
  168. static MErr MCompRestoreComponent(GravitySrvComp *self, MFileIOServ *file, long saveInfo, short rev)
  169. {
  170.     if ( rev == kGravitySrvRev ) {
  171.         MReadValue(file, &self->f_enableEvent);
  172.         MReadValue(file, &self->f_disableEvent);
  173.         MReadValue(file, &self->f_constant);
  174.         return kMNoCompErr;
  175.     }
  176.     else
  177.         return kMUnableToComplyCompErr;
  178. }
  179.  
  180.  
  181. /*    Process incoming message
  182. */
  183.  
  184. static MErr MCompProcessMessage(GravitySrvComp *self, MMessagePtr message)
  185. {
  186.     if ( MDetectMessage(message, self->f_enableEvent) ) {
  187.         short i, j;
  188.  
  189.         MRegisterGService(self, self, kMGeneralServiceKey);
  190.         MPostCTimeTask(self, nil, kTimePeriod, kGravitySrvSlot, kGravitySrvTask);
  191.         for (i=0; i<20; i++)
  192.             for ( j=0; j<20; j++) {
  193.                 self->f_table[i][j].f_x = 0.0;
  194.                 self->f_table[i][j].f_y = 0.0;
  195.             }
  196.         return kMNoCompErr;
  197.     }
  198.     else if ( MDetectMessage(message, self->f_disableEvent) || MDetectDisableMessage(message) ) {
  199.         MKillCTimeTask(self, nil);
  200.         MUnregisterGService(self, self);
  201.         return kMNoCompErr;
  202.     }
  203.     else
  204.         return kMUnableToComplyCompErr;
  205. }
  206.  
  207.  
  208. /*    Get component attribute
  209. */
  210.  
  211. static MErr MCompGetAttribute(GravitySrvComp *self, MomID attribName,  MDataType *selector, MDataType *dataValue)
  212. {
  213.     if ( MCmpMomID(attribName, kMEventsAttrib) && selector &&
  214.          selector->f_type.f_type == kMInteger ) {
  215.         switch (selector->f_integer.f_value & ~kMEventMask) 
  216.         {
  217.             case kMEventExecute:
  218.                 if ( (selector->f_integer.f_value & kMEventMask) == 1 ) {
  219.                     MCopyEvent(dataValue->f_event, self->f_enableEvent);
  220.                     return kMNoCompErr;
  221.                 }
  222.                 else
  223.                     return kMUnableToComplyCompErr;
  224.  
  225.             case kMEventTerminate:
  226.                 if ( (selector->f_integer.f_value & kMEventMask) == 1 ) {
  227.                     MCopyEvent(dataValue->f_event, self->f_disableEvent);
  228.                     return kMNoCompErr;
  229.                 }
  230.                 else
  231.                     return kMUnableToComplyCompErr;
  232.  
  233.             default:
  234.                 return kMUnableToComplyCompErr;
  235.         }
  236.     } 
  237.     else
  238.         return kMUnableToComplyCompErr;
  239. }
  240.  
  241.  
  242. /*    Adjust project-specific IDs
  243. */
  244.  
  245. static MErr MCompAdaptIDs(GravitySrvComp *self, MObjectPtr *sourceStore, MObjectPtr *targetStore)
  246. {
  247.     MTranslateID(kMTranslateEventID, sourceStore, targetStore, (MDataType *) &self->f_enableEvent);
  248.     MTranslateID(kMTranslateEventID, sourceStore, targetStore, (MDataType *) &self->f_disableEvent);
  249.     return kMNoCompErr;
  250. }
  251.  
  252.  
  253. /*    Gravity service task
  254. */
  255.  
  256. static MErr GravitySrvTask(GravitySrvComp *self, MTInfo *tinfo)
  257. {
  258.     short         i, j, numClients;
  259.     MDataType     dataVector, dataPosition, dataSize, dataMass;
  260.     MSelf        *client1, *client2;
  261.  
  262.     double        mass1, mass2, force, magnitude;
  263.     double        period, x, y, tempX, tempY;
  264.     double        midX, midY;
  265.  
  266.     double        posA_PNTX, posA_PNTY, posB_PNTX, posB_PNTY;
  267.  
  268.     PLPoint        size1, size2;
  269.  
  270.     MInitVector2D(dataVector.f_vector, 0.0, 0.0);
  271.     MInitPoint2D(dataPosition.f_point, 0, 0);
  272.     MInitPoint2D(dataSize.f_point, 0, 0);
  273.     MInitDouble(dataMass.f_double, 0.0);
  274.  
  275.     MGetNumClients(self, &numClients);
  276.  
  277.     if ( numClients > 1 && numClients < 21 ) {
  278.  
  279.         // build a table of forces between all bodies
  280.  
  281.         for (i = 0; i < numClients; i++) {
  282.             MGetNthClient(self, i, &client1);
  283.             if ( MError() != kMNoCompErr )
  284.                 return MError();
  285.  
  286.             MGetAttribute(client1, kMPositionAttrib, 0, &dataPosition);    // get info from 1st body
  287.             posA_PNTX = dataPosition.f_vector.f_angle;
  288.             posA_PNTY = dataPosition.f_vector.f_magnitude;
  289.             MGetAttribute(client1, kMSizeAttrib, 0, &dataSize);
  290.             size1 = dataSize.f_point.f_value;
  291.             MGetAttribute(client1, kMassAttrib, 0, &dataMass);
  292.             mass1 = dataMass.f_double.f_value;
  293.  
  294.             midX = posA_PNTX + (double) size1.PNTX / 2.0;
  295.             midY = posA_PNTY + (double) size1.PNTY / 2.0;
  296.  
  297.             for (j = 0; j < i; j++) {
  298.                 MGetNthClient(self, j, &client2);
  299.                 if ( MError() != kMNoCompErr )
  300.                     return MError();
  301.  
  302.                 MGetAttribute(client2, kMPositionAttrib, 0, &dataPosition);    // get info from 2nd body
  303.                 posB_PNTX = dataPosition.f_vector.f_angle;
  304.                 posB_PNTY = dataPosition.f_vector.f_magnitude;
  305.                 MGetAttribute(client2, kMSizeAttrib, 0, &dataSize);
  306.                 size2 = dataSize.f_point.f_value;
  307.                 MGetAttribute(client2, kMassAttrib, 0, &dataMass);
  308.                 mass2 = dataMass.f_double.f_value;
  309.  
  310.                 x = (posB_PNTX + (double) size2.PNTX / 2.0) - midX;
  311.                 y = (posB_PNTY + (double) size2.PNTY / 2.0) - midY;
  312.                 period =  x*x + y*y;
  313.                 magnitude = sqrt(period);    // calculate distance between bodies
  314.  
  315.                 if ( magnitude && mass1 && mass2 ) {    // distance plus both masses must exceed zero
  316.  
  317.                     force = self->f_constant.f_value * mass1 * mass2 / period;    // calculate force
  318.  
  319.                     tempX =  x / magnitude * force;
  320.                     tempY =  y / magnitude * force;
  321.  
  322.                     // calculate acceleration vector originiating from client1
  323.                     self->f_table[i][j].f_x    = tempX / mass1;
  324.                     self->f_table[i][j].f_y    = tempY / mass1;
  325.  
  326.                     // the acceleratrion vector originating from client2...
  327.                     // ...is the inverse of that from client1
  328.                     self->f_table[j][i].f_x    = -tempX / mass2;
  329.                     self->f_table[j][i].f_y    = -tempY / mass2;
  330.                 } 
  331.                 else {
  332.                     self->f_table[i][j].f_x    = self->f_table[i][j].f_y = 0.0;
  333.                     self->f_table[j][i].f_x    = self->f_table[j][i].f_y = 0.0;
  334.                 }
  335.             }
  336.         }
  337.  
  338.         // add all acceleration vectors acting on each body
  339.  
  340.         for (i = 0; i < numClients; i++) {
  341.             MGetNthClient(self, i, &client1);
  342.             if ( MError() != kMNoCompErr )
  343.                 return MError();
  344.  
  345.             x = y = 0.0;
  346.             for (j = 0; j < numClients; j++)
  347.                 if ( j != i ) {
  348.                     x = x + self->f_table[i][j].f_x;
  349.                     y = y + self->f_table[i][j].f_y;                        
  350.                 }
  351.             
  352.             dataVector.f_vector.f_angle = x;
  353.             dataVector.f_vector.f_magnitude    = y;
  354.             MSetAttribute(client1, kResVectorAttrib, 0, &dataVector);
  355.         }
  356.         return kMNoCompErr;
  357.  
  358.     } else
  359.         return kMUnableToComplyCompErr;
  360. }
  361.